arm: Tidy up flush_xen_dcache().
authorTim Deegan <tim@xen.org>
Fri, 23 Nov 2012 11:06:14 +0000 (11:06 +0000)
committerTim Deegan <tim@xen.org>
Fri, 23 Nov 2012 11:06:14 +0000 (11:06 +0000)
 - Use a compile-time-constant check for whether we can safely flush
   just one cacheline.  This reduces the common case from 28
   instructions to three.
 - Pass an object to the macro, not a pointer, so we can detect
   attempts to flush arrays.
 - Decode CCSIDR correctly to get cacheline size.
 - Remove some redundant DSBs at the call sites.

Signed-off-by: Tim Deegan <tim@xen.org>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Committed-by: Ian Campbell <ian.campbell@citrix.com>
xen/arch/arm/mm.c
xen/arch/arm/setup.c
xen/arch/arm/smpboot.c
xen/include/asm-arm/page.h
xen/include/xen/compiler.h

index b7d0a1cc382b36f2712d25197fe66f0b07e7e019..855f83d92bd2435dde151171844af925fd65d829 100644 (file)
@@ -247,7 +247,7 @@ void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr)
 
     /* Change pagetables to the copy in the relocated Xen */
     boot_httbr = (unsigned long) xen_pgtable + phys_offset;
-    flush_xen_dcache_va(&boot_httbr);
+    flush_xen_dcache(boot_httbr);
     flush_xen_dcache_va_range((void*)dest_va, _end - _start);
     flush_xen_text_tlb();
 
index c52330ee848c46355711b86628c5aaa37bde0482..20767246a5a39b68305d73c247ef413f142d5c74 100644 (file)
@@ -175,6 +175,21 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size)
     end_boot_allocator();
 }
 
+size_t __read_mostly cacheline_bytes;
+
+/* Very early check of the CPU cache properties */
+void __init setup_cache(void)
+{
+    uint32_t ccsid;
+
+    /* Read the cache size ID register for the level-0 data cache */
+    WRITE_CP32(0, CSSELR);
+    ccsid = READ_CP32(CCSIDR);
+
+    /* Low 3 bits are log2(cacheline size in words) - 2. */
+    cacheline_bytes = 1U << (4 + (ccsid & 0x7));
+}
+
 /* C entry point for boot CPU */
 void __init start_xen(unsigned long boot_phys_offset,
                       unsigned long arm_type,
@@ -185,6 +200,8 @@ void __init start_xen(unsigned long boot_phys_offset,
     size_t fdt_size;
     int cpus, i;
 
+    setup_cache();
+
     smp_clear_cpu_maps();
 
     fdt = (void *)BOOT_MISC_VIRT_START
index 05c8d8d22ce2db301587d0d845a8cacd00aee271..6555ac682ad32e1c71ba3916cb66ade4a7a7a2a8 100644 (file)
@@ -118,8 +118,8 @@ make_cpus_ready(unsigned int max_cpus, unsigned long boot_phys_offset)
         /* Tell the next CPU to get ready */
         /* TODO: handle boards where CPUIDs are not contiguous */
         *gate = i;
-        flush_xen_dcache_va(gate);
-        asm volatile("dsb; isb; sev");
+        flush_xen_dcache(*gate);
+        asm volatile("isb; sev");
         /* And wait for it to respond */
         while ( ready_cpus < i )
             smp_rmb();
@@ -217,8 +217,8 @@ int __cpu_up(unsigned int cpu)
     smp_up_cpu = cpu;
     /* we need to make sure that the change to smp_up_cpu is visible to
      * secondary cpus with D-cache off */
-    flush_xen_dcache_va(&smp_up_cpu);
-    asm volatile("dsb; isb; sev");
+    flush_xen_dcache(smp_up_cpu);
+    asm volatile("isb; sev");
 
     while ( !cpu_online(cpu) )
     {
index ed3bb5bbd65aba2dee16f4eed95b8ead2a7b282d..d89261e634ab1bcf005988fe64873c2572a0e909 100644 (file)
@@ -248,13 +248,16 @@ static inline void write_pte(lpae_t *p, lpae_t pte)
         : : "r" (pte.bits), "r" (p) : "memory");
 }
 
+/* Architectural minimum cacheline size is 4 32-bit words. */
+#define MIN_CACHELINE_BYTES 16
+/* Actual cacheline size on the boot CPU. */
+extern size_t cacheline_bytes;
 
 /* Function for flushing medium-sized areas.
  * if 'range' is large enough we might want to use model-specific
  * full-cache flushes. */
 static inline void flush_xen_dcache_va_range(void *p, unsigned long size)
 {
-    int cacheline_bytes  = READ_CP32(CCSIDR);
     void *end;
     dsb();           /* So the CPU issues all writes to the range */
     for ( end = p + size; p < end; p += cacheline_bytes )
@@ -262,17 +265,13 @@ static inline void flush_xen_dcache_va_range(void *p, unsigned long size)
     dsb();           /* So we know the flushes happen before continuing */
 }
 
-
 /* Macro for flushing a single small item.  The predicate is always
  * compile-time constant so this will compile down to 3 instructions in
- * the common case.  Make sure to call it with the correct type of
- * pointer! */
-#define flush_xen_dcache_va(p) do {                                     \
-    int cacheline_bytes  = READ_CP32(CCSIDR);                           \
-    typeof(p) _p = (p);                                                 \
-    if ( ((unsigned long)_p & ~(cacheline_bytes - 1)) !=                \
-        (((unsigned long)_p + (sizeof *_p)) & ~(cacheline_bytes - 1)) ) \
-        flush_xen_dcache_va_range(_p, sizeof *_p);                      \
+ * the common case. */
+#define flush_xen_dcache(x) do {                                        \
+    typeof(x) *_p = &(x);                                               \
+    if ( sizeof(x) > MIN_CACHELINE_BYTES || sizeof(x) > alignof(x) )    \
+        flush_xen_dcache_va_range(_p, sizeof(x));                       \
     else                                                                \
         asm volatile (                                                  \
             "dsb;"   /* Finish all earlier writes */                    \
index 28142bd4ba83cae2a29f91d1c48d066bdfd9813a..7009a0930be6dee74e3ffa4fd2516004792e16bf 100644 (file)
 
 #define offsetof(a,b) __builtin_offsetof(a,b)
 
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
+#define alignof __alignof__
+#endif
+
 /* &a[0] degrades to a pointer: a different type from an array */
 #define __must_be_array(a) \
   BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))